import * as Taro from '@tarojs/taro'
import mockData from '../../mock/index'
import { IResponse } from '../services/base'

// 错误码映射
const ERROR_MESSAGES: Record<number, string> = {
  400: '请求参数错误',
  401: '未授权，请重新登录',
  403: '拒绝访问',
  404: '请求的资源不存在',
  405: '请求方法不允许',
  408: '请求超时',
  500: '服务器内部错误',
  502: '网关错误',
  503: '服务不可用',
  504: '网关超时',
}

// 请求配置接口
interface RequestConfig {
  url: string
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
  data?: any
  header?: Record<string, string>
  timeout?: number
  useMock?: boolean // 是否强制使用 mock 数据
}

// 封装的请求方法
export const request = async <T = any>(config: RequestConfig): Promise<T> => {
  const { url, method = 'GET', data, header = {} } = config
  const useMock = false
  const useLocal = true
  let hasMockData = false
  const _data = data ? JSON.parse(JSON.stringify(data)) : {}

  if (useMock) {
    // 检查是否有对应的 mock 数据
    // 先尝试精确匹配（包含查询参数）
    let mockKey = `${method} ${url}`
    hasMockData = mockData[mockKey] !== undefined

    // 如果没有精确匹配，尝试匹配基础路径（去掉查询参数）
    if (!hasMockData && url.includes('?')) {
      const baseUrl = url.split('?')[0]
      mockKey = `${method} ${baseUrl}`
      hasMockData = mockData[mockKey] !== undefined
    }
  }

  const shouldUseMock = useMock && hasMockData

  try {
    if (useLocal) {
      const { data: responseData } = await Taro.request<IResponse<T>>({
        // url: `http://192.168.2.181:8080${url}`,
        url: `http://localhost:8080${url}`,
        method,
        data:_data,
        header: {
          'Content-Type': 'application/json',
          'x-wx-openid': '1312321312',
          ...header,
        },
      })

      return responseData.data
    } else if (shouldUseMock) {
      // 使用 mock 服务
      console.log(`[Mock] ${method} ${url}`, data)

      const { data: responseData } = await Taro.request<IResponse<T>>({
        url: `http://127.0.0.1:9527${url}`,
        method,
        data:_data,
        header: {
          'Content-Type': 'application/json',
          ...header,
        },
      })

      return responseData.data
    } else {
      const {
        data: { code, message, data: responseData },
      } = await Taro.cloud.callContainer<IResponse<T>>({
        path: url,
        method,
        data:_data,
        header: {
          'X-WX-SERVICE': 'dshx-back-end',
          // Cookie: `auth-token=${authToken.data}`, // 后端可以获取用户信息 前端不用认证
          ...header,
        },
      })
      if (code !== 'Success') {
        throw new Error(message)
      }

      return responseData
    }
  } catch (error: any) {
    console.error(`[Request Error] ${method} ${url}:`, error)

    // 处理不同类型的错误
    let errorMessage = '请求失败'
    let showToast = true

    if (error.errMsg) {
      // Taro 错误
      if (error.errMsg.includes('timeout')) {
        errorMessage = '请求超时，请检查网络连接'
      } else if (error.errMsg.includes('fail')) {
        errorMessage = '网络请求失败，请检查网络连接'
      } else {
        errorMessage = error.errMsg
      }
    } else if (error.statusCode) {
      // HTTP 状态码错误
      errorMessage = ERROR_MESSAGES[error.statusCode] || `请求失败 (${error.statusCode})`
    } else if (error.message) {
      // 其他错误
      errorMessage = error.message
    }

    // 显示错误提示
    if (showToast) {
      Taro.showToast({
        title: errorMessage,
        icon: 'none',
        duration: 3000,
      })
    }

    // 重新抛出错误，让调用方可以处理
    throw new Error(errorMessage)
  }
}

// 便捷的 GET 请求方法
export const get = <T = any>(url: string, config?: Omit<RequestConfig, 'url' | 'method'>) => {
  return request<T>({ ...config, url, method: 'GET' })
}

// 便捷的 POST 请求方法
export const post = <T = any>(url: string, data?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>) => {
  return request<T>({ ...config, url, method: 'POST', data })
}

// 便捷的 PUT 请求方法
export const put = <T = any>(url: string, data?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>) => {
  return request<T>({ ...config, url, method: 'PUT', data })
}

// 便捷的 DELETE 请求方法
export const del = <T = any>(url: string, config?: Omit<RequestConfig, 'url' | 'method'>) => {
  return request<T>({ ...config, url, method: 'DELETE' })
}
